﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;

namespace timetable
{
    [Serializable]
    public class TeacherAndClassroom
    {
        public Queue<int> Classrooms = new Queue<int>(10);
        public Dictionary<string, Queue<int>> TeacherDictionary;
        private static readonly string[] Coursename =
        {
            "语文", "数学", "英语", "物理", "化学", "生物", "政治", "历史", "地理", "通技"
        };

        HSSFWorkbook book = new HSSFWorkbook();

        private List<HashSet<int>> teacherLists = new List<HashSet<int>>();
        public List<List<string>> teacherListsStr;
        public List<List<List<string>>> AllTeacherList = new List<List<List<string>>>();

        private List<string> courses;
        private int[,] matrics;
        private int[,] rawMatrix;
        public TeacherAndClassroom()
        {

            // TODO 从数据库或者文件中直接读取，然后使用LINQ语句进行生成最后形式的变量

            // 初始化教师数据
            TeacherDictionary = new Dictionary<string, Queue<int>>();
            Queue<int> course = new Queue<int>();
            for (int i = 101; i <= 160; i++)
            {
                if (i == 101)
                {
                    course = new Queue<int>(8);
                    TeacherDictionary.Add("语文", course);
                }

                if (i == 109)
                {
                    course = new Queue<int>(7);
                    TeacherDictionary.Add("数学", course);
                }

                if (i == 116)
                {
                    course = new Queue<int>(6);
                    TeacherDictionary.Add("英语", course);
                }
                if (i == 122)
                {
                    course = new Queue<int>(4);
                    TeacherDictionary.Add("政治", course);
                }
                if (i == 126)
                {
                    course = new Queue<int>(4);
                    TeacherDictionary.Add("历史", course);
                }
                if (i == 130)
                {
                    course = new Queue<int>(4);
                    TeacherDictionary.Add("地理", course);
                }
                if (i == 134)
                {
                    course = new Queue<int>(4);
                    TeacherDictionary.Add("物理", course);
                }
                if (i == 138)
                {
                    course = new Queue<int>(4);
                    TeacherDictionary.Add("化学", course);
                }
                if (i == 142)
                {
                    course = new Queue<int>(5);
                    TeacherDictionary.Add("生物", course);
                }
                if (i == 147)
                {
                    course = new Queue<int>(4);
                    TeacherDictionary.Add("体育", course);
                }
                if (i == 151)
                {
                    course = new Queue<int>(2);
                    TeacherDictionary.Add("音乐", course);
                }
                if (i == 153)
                {
                    course = new Queue<int>(2);
                    TeacherDictionary.Add("美术", course);
                }
                if (i == 155)
                {
                    course = new Queue<int>(4);
                    TeacherDictionary.Add("通技", course);
                }
                course.Enqueue(i);
            }

            // 初始化教室数据
            for (int i = 101; i < 111; i++)
            {
                Classrooms.Enqueue(i);
            }
        }

        public void AllocateTeacherClass(EnergyTable betterEnergyTable, string discipline)
        {

            int classSum = 0; // 该门课程总共的班级数
            courses = new List<string>();
            // 遍历获取该科课程的所有班级
            foreach (GroupList list in betterEnergyTable.CompareList)
            {
                foreach (string s in list.CourseSet)
                {
                    if (s.Substring(0, 2) == discipline && !courses.Contains(s))
                    {
                        courses.Add(s);
                        classSum++;
                    }
                }
            }

            matrics = new int[classSum, classSum];

            // 开始标记一起上课的课程
            for (int i = 0; i < betterEnergyTable.Count; i++)
            {
                List<Dictionary<string, List<string>>> list = betterEnergyTable[i];
                foreach (Dictionary<string, List<string>> dictionary in list)
                {
                    List<string> classList;
                    if (dictionary.TryGetValue(discipline, out classList))
                    {
                        // 存储这一节课的一起上的班级索引
                        int[] subInts = new int[classList.Count];
                        for (int j = 0; j < classList.Count; j++)
                        {
                            int subscript = courses.IndexOf(classList[j]);
                            if (subscript != -1)
                            {
                                subInts[j] = subscript;
                            }

                        }

                        // 将索引对应的矩阵位置的值设为1
                        foreach (int subInt in subInts)
                        {
                            foreach (int subInt1 in subInts)
                            {
                                matrics[subInt1, subInt] = 1;
                            }
                        }


                    }

                }
            }

            // 将matrics原始数据进行存储
            rawMatrix = (int[,])matrics.Clone();
            // 获取每一个班级不能够同时上课的集合
            List<HashSet<int>> cannotTogetherList = new List<HashSet<int>>(classSum);
            for (int i = 0; i < classSum; i++)
            {
                HashSet<int> cannotTogether = new HashSet<int>();
                for (int j = 0; j < classSum; j++)
                {
                    if (matrics[i, j] == 1)
                    {
                        cannotTogether.Add(j);

                    }
                }
                cannotTogetherList.Add(cannotTogether);
            }

            // 开始第一次分配教师班级       
            CalculateTeacher(matrics, classSum);

            // 一个老师能够上的班级
            List<HashSet<int>> ATeacherCanTeachSet = new List<HashSet<int>>(teacherLists.Count);
            foreach (HashSet<int> teacherList in teacherLists)
            {
                HashSet<int> ATeacherSet = new HashSet<int>(teacherList);
                ATeacherCanTeachSet.Add(ATeacherSet);
            }

            // 开始尝试重新分配非混合班
            // 拷贝一个用来尝试重新排班的教师集合
            List<HashSet<int>> exchangedSetList = new List<HashSet<int>>(ATeacherCanTeachSet.Count);
            foreach (HashSet<int> hashSet in ATeacherCanTeachSet)
            {
                exchangedSetList.Add(new HashSet<int>(hashSet));
            }

            Console.WriteLine("请打开教师班级对照表对老师进行手动分班");

            // 首先自动分班，然后开始手动分班
            for (int n = 0; n < exchangedSetList.Count; n++)
            {

                // 一个一个的拿出来看看能不能插入到别的分组里边去
                foreach (int i in exchangedSetList[n])
                {

                    exchangedSetList = new List<HashSet<int>>(ATeacherCanTeachSet.Count);
                    foreach (HashSet<int> hashSet in ATeacherCanTeachSet)
                    {
                        exchangedSetList.Add(new HashSet<int>(hashSet));
                    }

                    // 计算去除特定班级后，剩余的分组哪个还能够容纳这个班级
                    // 从最后一个分组开始找起
                    // 倒着找，终点为抽出特定班级的那个分组
                    for (int j = exchangedSetList.Count - 1; j >= n; j--)
                    {
                        int counts = 0;
                        foreach (int i1 in exchangedSetList[j])
                        {
                            // 如果某个班级不能够和选出来的班级一起上课的话
                            // 那么这个分组都不能
                            if (cannotTogetherList[i1].Contains(i) || cannotTogetherList[i].Contains(i1))
                            {
                                break;
                            }
                            counts++;
                        }
                        // 如果该分组遍历之后没有包含特定班级
                        // 说明该班级可以加入该分组
                        if (counts == exchangedSetList[j].Count)
                        {
                            // 将该班级加入新的分组
                            // 并且从原来分组中删除
                            exchangedSetList[j].Add(i);
                            exchangedSetList[n].Remove(i);

                            // 比较新旧两种分组方式的能量值
                            int oldEnergyValue = 0;
                            foreach (HashSet<int> set in ATeacherCanTeachSet)
                            {
                                oldEnergyValue += set.Count*set.Count;
                            }
                            int newEnergyValue = 0;
                            foreach (HashSet<int> set in exchangedSetList)
                            {
                                newEnergyValue += set.Count*set.Count;
                            }

                            // 若能量值减小
                            // 接受新的分组方案
                            if (oldEnergyValue > newEnergyValue)
                            {
                                ATeacherCanTeachSet = exchangedSetList;
                                break; //已经找到了，跳出循环
                            }
                            else // 否则就将之前的修改还原，寻找下一个分组看能不能加入
                            {
                                exchangedSetList[j].Remove(i);
                                exchangedSetList[n].Add(i);
                            }


                        } // if (count == exchangedSetList[j].Count)
                    } //  for (int j = exchangedSetList.Count - 1; j >= n; j--)

                } // foreach (int i in exchangedSetList[n])
            } //for (int n = 0; n < exchangedSetList.Count; n++)
            // 将能量最小化之后的分组结果重新写入teacherLists中

            // 自动分班模式结束

            Console.WriteLine("当前的教师分班课程为  " + discipline);
            // 输出分班结果

            teacherLists = ATeacherCanTeachSet;
            //将分组中的编号还原成班级
            teacherListsStr = new List<List<string>>(teacherLists.Count);
            foreach (HashSet<int> teacherList in teacherLists)
            {
                List<string> classes = teacherList.Select(i => courses[i]).ToList();
                teacherListsStr.Add(classes);
            }
            // 输出结果到终端中
            for (int i = 0; i < teacherListsStr.Count; i++)
            {
                Console.WriteLine("第{0}组", i);
                foreach (string s in teacherListsStr[i])
                {

                    int classIndex = courses.IndexOf(s);
                    Console.WriteLine("{0}  {1}  {2}", classIndex, "教师" + (char) (65 + i), s);
                }
                Console.WriteLine();

            }

            //// 手动给老师分配班级

            //Console.WriteLine("请输入需要调整位置的班级编号以及插入的分组编号（例如：第1组班级编号为5的换到第3组就输入1,5,3）");

            //string[] sArray = null;
            //do
            //{
            //    sArray = Console.ReadLine().Split(',');
            //} while (sArray[0] == "");

            //int[] iArray = new int[sArray.Length];
            //for (int i = 0; i < iArray.Length; i++)
            //{
            //    iArray[i] = int.Parse(sArray[i].Replace("\b", ""));
            //}
            //int originalGroup = iArray[0];
            //int classNumber = iArray[1];
            //int desGroup = iArray[2];

            //Console.WriteLine("正在处理中，请稍后...");
            //// 创建一个存储用户选择分组的变量
            //exchangedSetList = new List<HashSet<int>>(ATeacherCanTeachSet.Count);
            //foreach (HashSet<int> hashSet in ATeacherCanTeachSet)
            //{
            //    exchangedSetList.Add(new HashSet<int>(hashSet));
            //}

            //// 首先看看要加入的分组会有和班级有冲突
            //int count = 0;

            //foreach (int i1 in exchangedSetList[desGroup])
            //{
            //    // 如果某个班级不能够和选出来的班级一起上课的话
            //    // 那么这个分组都不能
            //    if (cannotTogetherList[classNumber].Contains(i1)
            //        || cannotTogetherList[i1].Contains(classNumber))
            //    {
            //        break;
            //    }
            //    count++;
            //}

            //// 如果该分组遍历之后没有包含特定班级
            //// 说明该班级可以加入该分组
            //if (count == exchangedSetList[desGroup].Count)
            //{
            //    // 将该班级加入新的分组
            //    // 并且从原来分组中删除
            //    Console.WriteLine("该方案可以安排，是否确认？(y/n)");
            //    //Console.ReadLine()

            //    string result = null;
            //    if (result == "y")
            //    {

            //        exchangedSetList[desGroup].Add(classNumber);
            //        exchangedSetList[originalGroup].Remove(classNumber);
            //        ATeacherCanTeachSet = exchangedSetList;
            //        Console.WriteLine("修改成功！");
            //    }
            //}
            //else
            //{
            //    Console.WriteLine("该方案不能安排，请尝试更换方案");
            //}

            AllTeacherList.Add(teacherListsStr);
        }


        public void OutputTeachers(EnergyTable betterEnergyTable, List<GroupListClass> GroupListClasses, Dictionary<string, int> studentAmountEachClass, string discipline)
        {

            string sheetName = discipline;
            ISheet sheet;
            try
            {
                sheet = book.CreateSheet(sheetName);
            }
            catch (Exception)
            {
                sheetName += new Random().Next(10);
                sheet = book.CreateSheet(sheetName);
            }


            int m = 0;
            for (int i = 0; i < teacherListsStr.Count; i++)
            {
                m += 1;
                for (int j = 0; j < teacherListsStr[i].Count; j++)
                {
                    m += 1;
                    IRow row = sheet.CreateRow(m);
                    row.CreateCell(0)
                    .SetCellValue("教师" + (char)(65 + i));
                    row.CreateCell(1)
                        .SetCellValue(teacherListsStr[i][j]);
                    // 寻找对应班级人数

                    foreach (KeyValuePair<string, int> pair in studentAmountEachClass)
                    {
                        if (pair.Key == teacherListsStr[i][j])
                        {
                            row.CreateCell(2)
                                .SetCellValue(pair.Value);
                            break;
                        }
                    }

                    // 寻找对应班级的教室
                    foreach (GroupListClass groupListClass in GroupListClasses)
                    {
                        int classroomNumber;
                        groupListClass.CommonClass.TryGetValue(teacherListsStr[i][j], out classroomNumber);
                        if (classroomNumber != 0)
                        {
                            row.CreateCell(3)
                                .SetCellValue(classroomNumber);
                            break;
                        }
                        groupListClass.SpecialList.TryGetValue(teacherListsStr[i][j], out classroomNumber);
                        if (classroomNumber != 0)
                        {
                            row.CreateCell(3)
                                .SetCellValue(classroomNumber);
                            break;
                        }
                    }

                    // 将教师信息加入到courseCell中
                    foreach (GroupList list in betterEnergyTable.CompareList)
                    {
                        foreach (Group @group in list.List)
                            foreach (List<CourseCell> cells in group.Curriculum.table)
                                foreach (CourseCell cell in cells)
                                    if (cell.Class == teacherListsStr[i][j])
                                        cell.TeacherId = discipline + (char)(65 + i);
                    }
                }
            }
            

        }

        public void WriteToExcel(string filePath)
        {
            // 写入到客户端  
            using (MemoryStream ms = new MemoryStream())
            {
                book.Write(ms);
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                {
                    byte[] data = ms.ToArray();
                    fs.Write(data, 0, data.Length);
                    fs.Flush();
                }
                book = null;
            }
        }
            


        private void CalculateTeacher(int[,] matrics, int classSum)
        {
            teacherLists = new List<HashSet<int>>();

            for (int j = 0; j < classSum; j++) //确定能够和第j班分配给一个老师的班
            {
                HashSet<int> teacherClassList = new HashSet<int>();
                for (int k = 0; k < classSum; k++)
                {
                    // 只有能够和j班不冲突的时候，再寻找下一个和这两班都不冲突的班级
                    if (matrics[j, k] == 0)
                    {
                        teacherClassList.Add(j);
                        teacherClassList.Add(k);
                        for (int i = 0; i < classSum; i++)
                        {
                            if (matrics[k, i] == 1)
                                matrics[j, i] = 1;
                        }
                    }
                }
                if (teacherClassList.Count > 0)
                {
                    teacherLists.Add(teacherClassList);
                }


                // 将已经分出来的班级的行和列全部设置为1
                foreach (int i in teacherClassList)
                {
                    for (int k = 0; k < classSum; k++)
                    {
                        matrics[i, k] = 1;
                        matrics[k, i] = 1;
                    }
                }
            }

            // 将剩下的没有分组的班级每个班级一个老师
            HashSet<int> allClass = new HashSet<int>();
            for (int i = 0; i < classSum; i++)
            {
                allClass.Add(i);
            }

            foreach (HashSet<int> teacherList in teacherLists)
            {
                allClass.ExceptWith(teacherList);
            }

            foreach (int i in allClass)
            {
                teacherLists.Add(new HashSet<int>() { i });
            }

        }

        // 输出课程冲突表
        public void OutputTeacherConlictTable(string filePath,string discipline)
        {
            HSSFWorkbook book = new HSSFWorkbook();
            ISheet sheet = book.CreateSheet(discipline);

            // 输出冲突矩阵
            IRow ir = sheet.CreateRow(0);
            for (int i = 0; i < Math.Sqrt(rawMatrix.Length); i++)
            {
                ir.CreateCell(i+1).SetCellValue(i);
            }

            for (int i = 0; i < Math.Sqrt(rawMatrix.Length); i++)
            {
                IRow irrawMatrix = sheet.CreateRow(i + 1);
                irrawMatrix.CreateCell(0).SetCellValue(i);
                for (int j = 0; j < Math.Sqrt(rawMatrix.Length); j++)
                {
                    if (rawMatrix[i, j] == 1)
                        irrawMatrix.CreateCell(j + 1).SetCellValue(1);
                    else irrawMatrix.CreateCell(j + 1).SetCellValue(0);
                }
            }
            // 输出冲突矩阵代号对应的课程名称
            IRow courseRow = sheet.CreateRow(sheet.LastRowNum + 1);
            courseRow.CreateCell(0).SetCellValue("课程代号");
            courseRow.CreateCell(1).SetCellValue("课程名称");

            int lastRow = sheet.LastRowNum;
            for (int i = 0; i < courses.Count; i++)
            {
                IRow courseName = sheet.CreateRow(lastRow + i + 1);
                courseName.CreateCell(0).SetCellValue(i);
                courseName.CreateCell(1).SetCellValue(courses[i]);
            }

            using (MemoryStream ms = new MemoryStream())
            {
                book.Write(ms);
                using (FileStream fs = new FileStream(filePath+discipline+".xls", FileMode.Create, FileAccess.Write))
                {
                    byte[] data = ms.ToArray();
                    fs.Write(data, 0, data.Length);
                    fs.Flush();
                }
                book = null;
            }


        }

    }
}
